/*
 *	Copyright (C) 2008 CRIMERE
 *	Copyright (C) 2008 Jean-Marc Mercier
 *	
 *	This file is part of OTS (optimally transported schemes), an open-source library
 *	dedicated to scientific computing. http://code.google.com/p/optimally-transported-schemes/
 *
 *	CRIMERE makes no representations about the suitability of this
 *	software for any purpose. It is provided "as is" without express or
 *	implied warranty.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#if !defined(_Tadmor_)
#define _Tadmor_
#include <src/math/BoundaryCondition/classicalgraphdefinition.h>
#include <src/math/Operators/FiniteDifferenceOperators.h>
#include <src/algorithm/Evolution_Algorithm/CFL_traits.h>
#include <src/algorithm/Evolution_Algorithm/Predictor_traits.h>


/*! \brief Non compilable Tadmor fluxes class

	Non compilable class : It is the Tadmor non linear fluxes check dimensionality class.
*/
template <class data, std::size_t = data::Dim >
class Tadmor 
 {
//! return " Tadmor u" \f$.
		OS_STATIC_CHECK(false); // to implement
};

/*! \brief Tadmor fluxes

    Tadmor non linear fluxes are computed from a non linear function \f$\sigma(u)\f$ : Let \f$\{u^0,u^1\}_i\f$ be two arrays of vector,
    then the Tadmor flux \f$\sigma^*(u^0,u^1)\f$ is the vector
    \f[
            \sigma^*(u^0,u^1) = \{\frac{\int_{u^0_i}^{u^1_i}\sigma(s)ds}{u^1_i-u^0_i}\}_i
    \f]
    Thus the Tadmor class constructor takes a function as input. Pre-requisite : \f$\sigma(u)\f$ must be explicitely integrable, the dimension of the vector must be one.
*/
template <class data>
class Tadmor<data,1> : public operator_binary_base<data,data> 
{
public :
		enum:std::size_t												{Order = 1};
		typedef Tadmor													type;
		typename typedef data::value_type								value_type;
		typedef integrable<value_type,value_type>						function_type;
		typedef typename function_type::Base							integrable_type;
		typedef typename data::size_type								size_type;
		typedef smart_ptr<function_type>								smart_ptr_function_type;

//! return " Tadmor " \f$.
		static std::string get_name(){return " Tadmor";};
		Tadmor( smart_ptr<function_type> f) : 
			f_( f ), f_int_( f_->get_integral() ) 
		{} ;
		virtual data operator()(const data & left, const data & right) const
		{
			typedef typename data::size_type size_type;
			typedef typename data::const_iterator const_iterator;
			typedef typename data::iterator iterator;
			const function_type & f = *f_;
			const integrable_type & f_int = *f_int_;
			size_type size = left.size();
			OS_DYNAMIC_CHECK(size = right.size(),"Tadmor : incompatible size");
			data result(size);
			if (size >0){
				const_iterator beg	= left.begin();
				const_iterator beg_right = right.begin();
				const_iterator end = left.end();
				iterator it = result.begin();
				for (;beg != end;++beg,++beg_right,++it) {
					if ((*beg) == (*beg_right))
						(*it) = f(*beg);
					else
						(*it) = (f_int(*beg_right)-f_int(*beg))/(*beg_right - *beg);
				};
			};
			return result;
		};
		smart_ptr<function_type> f_;
		smart_ptr<integrable_type> f_int_;
};
#endif